package omm.domain.evolutiongraph;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import omm.domain.CommissionStrategy;
import omm.domain.Graphic;
import omm.domain.Quotation;
import omm.util.Graphics;

import org.joda.time.DateTime;

public class EvolutionGraphic implements Graphic {

	final private PeriodStrategy period;
	final private CommissionStrategy commision;
	final private UnitStrategy unit;
	
	private List<Quotation> quotations;
	private String urlformat = "http://chart.apis.google.com/chart?chs=430x250" + /*420x150*/
			"&amp;chd=t:%s&amp;cht=bvg" + // Porcentajes de cada barra con respecto al maximo
			"&amp;chco=8b0027" + 
			"&amp;chbh=%d,0,%d" + // Ancho de barra
			"&amp;chxt=y,x,x" + 
			"&amp;chxl=0:|0|%s|1:%s" +// Nombres de los ejes en el orden de chxt
			"&amp;chxs=0,000000,17,0,l,000000,000000|1,000000,17,0,l,000000,000000|2,000000,17,0,l,000000,000000" + //Formato de los ejes
			"&amp;chtt=%s&amp;chts=000000,18,c" + //Titulo y su formato
			"&amp;chxp=0,0"; //Axis bien distribuido

	public EvolutionGraphic(List<Quotation> quotations, PeriodStrategy periodStrategy,
			CommissionStrategy commisionStrategy, UnitStrategy unitStrategy) {
		this.period = periodStrategy;
		this.commision = commisionStrategy;
		this.unit = unitStrategy;
		this.quotations = quotations;

	}

	/**
	 * Devuelve la URL del grafico
	 * @return URL de grafico de evolucion
	 */
	@Override
	public String getGraphicURL() {

		Map<DateTime, Double> periodsValue = unit.calculateByPeriod(quotations, period, commision);
		Integer barWidth = period.calculateBarsWidth();
		
		//String dimensions = period.calculateDimensions();
		//String dimensions = "280x200";
		Integer maxYAxis = calculateMaxYAxis(periodsValue);
		String barsPercentage = calculateBarsPercentages(periodsValue, maxYAxis);
		String yAxis = calculateYAxis(maxYAxis);
		
		//TODO: Mejorar
		DateTime start=null, end=null;
		boolean isfirst = true;
		for (Map.Entry<DateTime, Double> e : periodsValue.entrySet()) {
			if(isfirst){
				start = e.getKey();
				isfirst = false;
			}
			end = e.getKey();
		}
		
		String title = unit.getTitle(commision);
		Integer barSpace = period.calculateBarsSeparation();
		
		String periodsNames= giveNiceFormatToPeriodsNames(period.calculatePeriodsNames(periodsValue), "2:|");
					
		Object[] params = { barsPercentage, barWidth, barSpace, yAxis, periodsNames, title };
		return String.format(urlformat, params);
	}

	/**
	 * Devuelve los periodos divididos en 2 grupos separados por el separator
	 * 
	 * @param periodValue
	 *            Map con clave numero de periodo y valor de cada periodo
	 * @param separator
	 *            El separador entre los 2 grupos
	 * @return Periodos divididos en 2 grupos separados por el separator
	 */
	//|4/11||5/11||6/11||7/11||8/11||9/11|2:||10/11||11/11||12/11||1/12||2/12||3/12
	private String giveNiceFormatToPeriodsNames(String periodsValue, String separator) {
		String[] p = periodsValue.split("\\|");
		//Si hay menos de 10 periodos no se dividen en 2 
		if (p.length < 10) return "|" + periodsValue + "|" + separator;		
		String odds= "", evens="";
		for(int i = 0; i < p.length; i++ ){
			if( i % 2 == 0 ){
				odds += "|" + p[i] + "|";
			}else{
				evens += "|" + p[i] + "|";
			}
		}
		String periodsNames = odds + separator + evens;
		return periodsNames.substring(0, periodsNames.length() - 1);
	}

	/**
	 * Devuelve el parametro del grafico que indica los porcentajes
	 * 
	 * @param periodValue
	 *            Map con clave numero de periodo y valor de cada periodo
	 * @param maxYAxis
	 *            El maximo valor que se toma
	 * @return Parametro del grafico que indica los porcentajes
	 */
	private String calculateBarsPercentages(Map<DateTime, Double> periodsValue, Integer maxYAxis) {
		String percentages = "";
		if (maxYAxis == 0) {
			for (int i = 0; periodsValue.size() > i; i++) {
				percentages += "0,";
			}
		} else {
			for (Map.Entry<DateTime, Double> e : periodsValue.entrySet()) {
				Double value = e.getValue();
				//System.out.println(e.getKey().toString()+"->"+value);
				// TODO:Ver si round perl
				Integer percentage = (int) (value * 100 / maxYAxis);
				percentages = percentages + percentage.toString() + ',';
			}
		}
		return percentages.substring(0, percentages.length() - 1);
	}

	/**
	 * Calcula el maximo que debera tener el eje Y
	 * 
	 * @param periodsValue
	 *            Map con clave numero de periodo y valor de cada periodo
	 */
	private Integer calculateMaxYAxis(Map<DateTime, Double> periodsValue) {
		Iterator<Double> iterator = periodsValue.values().iterator();
		
		Double maxValue = 0.0;
		while (iterator.hasNext()) {
			Double actualValue = iterator.next();
			if (maxValue < actualValue) {
				maxValue = actualValue;
			}
		}
		int om = 1;
		if (maxValue > 0) {
			while (om <= maxValue) {
				om *= 10;
			}
			om /= 10;
		} else {
			maxValue = 0.0;
		}

		
		// maximo redondeado a la magnitud obtenida
		Integer maxYAxis = (int) ((maxValue % om == 0) ? Math.ceil(maxValue) : maxValue - (maxValue % om)
				+ om);
		return maxYAxis;
	}

	/**
	 * Devuelve el parametro del grafico que indica el y-axis
	 * 
	 * @param maxYAxis
	 *            El maximo valor que toma el eje
	 * @return Parametro del grafico que indica el y-axis
	 */
	private String calculateYAxis(Integer maxYAxis) {
		maxYAxis = unit.calculateMaxYAxis(maxYAxis);
		int firstParam = (int) (maxYAxis * 0.25);
		int secondParam = (int) (maxYAxis * 0.50);
		int thirdParam = (int) (maxYAxis * 0.75);
		int fourthParam = (int) (maxYAxis);
		String yAxisformat = "%d|%d|%d|%d";
		Object[] params = { firstParam, secondParam, thirdParam, fourthParam };
		return String.format(yAxisformat, params);
	}

	public DateTime getStart() {
		return period.getBegin();
	}

	public DateTime getEnd() {
		return period.getEnd();
	}

}
